﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Com.CloudTalk.Data;
using System.Data.Objects;
using System.Web.Script.Serialization;

namespace Com.CloudTalk.Controller
{
    public class CTClient
    {
        private List<CTEvent> m_lstSentMessages = new List<CTEvent>();
        private List<CTEvent> m_lstReceivedMessages = new List<CTEvent>();
        private CloudTalkEntities context;
        private Client entityClient;
        
        public string Name { get; set; }
        public string Email { get; set; }

        public List<CTEvent> SentMessages 
        {
            get
            {
                if (!this.entityClient.MessagesSent.IsLoaded)
                {
                    this.entityClient.MessagesSent.Load();
                    
                    this.entityClient.MessagesSent.ToList()
                        .ForEach(m =>
                        {
                            m.SenderReference.Load();
                            m.RecipientReference.Load();

                            this.m_lstSentMessages.Add(new CTEvent(m));
                        });
                }

                return this.m_lstSentMessages;
            }
        }
        public List<CTEvent> ReceivedMessages 
        {
            get
            {
                if (!this.entityClient.MessagesReceived.IsLoaded)
                {
                    this.entityClient.MessagesReceived.Load();

                    this.entityClient.MessagesReceived.ToList()
                        .ForEach(m =>
                        {
                            m.SenderReference.Load();
                            m.RecipientReference.Load();

                            this.m_lstReceivedMessages.Add(new CTEvent(m));
                        });
                }

                return this.m_lstReceivedMessages;
            }
        }

        public CTClient(
            string _sName,
            string _sEmail)
        {
            this.Email = _sEmail;
            this.Name = _sName;

            this.RefreshData();
        }

        private void RefreshData()
        {
            if (this.context != null)
            {
                this.context.Dispose();
            }
            this.context = new CloudTalkEntities();

            this.entityClient = this.context.Client.FirstOrDefault(cl => cl.Email == this.Email);
            this.m_lstReceivedMessages.Clear();
            this.m_lstSentMessages.Clear();

            if (this.entityClient == null)
            {
                throw new InvalidOperationException("Client not found");
            }
        }

        internal void RegisterEvent(
            object _msg,
            string _sRecipientEmail,
            EventType _eType,
            CTChatRoom _room)
        {
            Client recptClient = context.Client.FirstOrDefault(cl => cl.Email == _sRecipientEmail);
            JavaScriptSerializer jss = new JavaScriptSerializer();

            if (recptClient == null)
            {
                throw new InvalidOperationException("Provided recipient does not exist");
            }

            Event newMsg = null;

            switch (_eType)
            {
                case EventType.Message:
                    newMsg = new MessageEvent();
                    break;
                case EventType.EnterRoom:
                    newMsg = new EnterRoomEvent();
                    break;
                case EventType.LeaveRoom:
                    newMsg = new LeaveRoomEvent();
                    break;
                case EventType.RoomSpaceAvailable:
                    newMsg = new RoomSpaceAvailableEvent();
                    break;
                case EventType.QueueSizeChanged:
                    newMsg = new QueueSizeChangedEvent();
                    break;
            }

            DateTime timestamp = DateTime.Now;

            newMsg.Text = jss.Serialize(_msg);
            newMsg.Sender = entityClient;
            newMsg.Recipient = recptClient;
            newMsg.Timestamp = timestamp;

            entityClient.MessagesSent.Add(newMsg);

            context.SaveChanges();

            this.SentMessages.Add(new CTEvent(newMsg));

            context.AddToHistory(new History() 
            { 
                Client = entityClient,
                Room = _room.Name,
                Text = _msg.ToString(),
                Timestamp = timestamp
            });

            context.SaveChanges();
        }

        internal void RegisterEvent(
            object _msg,
            EventType _eType,
            CTChatRoom _room)
        {
            // allow a client that just left the room to send a message telling this
            if (_eType != EventType.LeaveRoom &&
                _room.ClientList.FirstOrDefault(cl => cl.Email == this.Email) == null)
            {
                throw new ArgumentException("The client must be a member of the room");
            }

            foreach (CTClient client in _room.ClientList)
            {
                if (client.Email != this.Email)
                {
                    this.RegisterEvent(_msg, client.Email, _eType, _room);
                }
            }
        }

        internal List<CTEvent> Receive()
        {
            this.RefreshData();

            List<CTEvent> retList = new List<CTEvent>(this.ReceivedMessages.Count());
            retList.AddRange(this.ReceivedMessages);

            this.entityClient.MessagesReceived.ToList()
                .ForEach(m =>
                {
                    this.context.DeleteObject(m);
                });

            this.context.SaveChanges();
            
            return retList;
        }

        internal static Client GetClientByEmail(string _sEmail)
        {
            if (String.IsNullOrEmpty(_sEmail))
            {
                throw new ArgumentNullException();
            }

            using (CloudTalkEntities db = new CloudTalkEntities())
            {
                Client c = db.Client.FirstOrDefault(cl => cl.Email == _sEmail);

                if (c != null)
                {
                    db.Detach(c);
                    return c;
                }

                return null;
            }
        }

        ~CTClient()
        {
            if (this.context != null)
            {
                this.context.Dispose();
            }
        }
    }
}
